package com.tq.core;


import lombok.Builder;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 抽象万物
 *
 * @author TqCoder
 * @since 2.0.0
 */
public class AbstractStruct {

    @Builder
    record  StackFrame(

            String methodName,

            String invokeMethodName
    ){

    }

    public static void main(String[] args) {
        Stack<StackFrame> stack = new Stack<>();
        initEl(stack);
        validateEl(stack);
        actuator(stack);
    }

    private static void actuator(Stack<StackFrame> stack) {
        while (!stack.isEmpty()){
            StackFrame pop = stack.pop();
            System.out.println("methodName: " + pop.methodName + " invokeMethodName: " + pop.invokeMethodName);
            if(pop.invokeMethodName != null){
                StackFrame frame = StackFrame.builder()
                        .methodName(pop.invokeMethodName)
                        .invokeMethodName(pop.methodName)
                        .build();
                stack.push(frame);
            }
        }
    }

    private static void initEl(Stack<StackFrame> stack) {
        StackFrame frameC = StackFrame.builder()
                .methodName("methodC")
                .invokeMethodName(null)
                .build();
        stack.push(frameC);

        StackFrame frameB = StackFrame.builder()
                .methodName("methodB")
                .invokeMethodName("methodC")
                .build();
        stack.push(frameB);

        StackFrame frameA = StackFrame.builder()
                .methodName("methodA")
                .invokeMethodName("methodB")
                .build();
        stack.push(frameA);

    }

    static void validateEl(Stack<StackFrame> stack){
        // K - stackFrameName  V - invokeMethodName
        Map<String, String> invokedMethodMap = stack.stream()
                .filter(stackFrame -> stackFrame.invokeMethodName != null)
                .collect(Collectors.toMap(
                        stackFrame -> stackFrame.methodName,
                        stackFrame -> stackFrame.invokeMethodName
                ));
        for (Map.Entry<String, String> entry : invokedMethodMap.entrySet()) {
            String value = entry.getValue();
            if(invokedMethodMap.containsKey(value)){
                throw new RuntimeException("存在循环依赖");
            }
        }
    }

    // ------------------------------------------ DAG ------------------------------------------------------------------

    /**
     * 有向无环图
     */
    static class DAG {

        private List<Node> nodes;

        private List<Edge> edges;

        static class Node {
            private String name;
        }

        static class Edge {
            private String from;
            private String to;
        }
    }


    // ------------------------------------------ SPI ------------------------------------------------------------------
    // Service Provider Interface
    // module jar 依赖了 api pom 包 我希望启动时候能够自动扫描到 api 包下的所有实现类
    // ServiceLoader来实现的，定义元数据，启动生命周期，会去扫描


    //------------------------------------------- Summary --------------------------------------------------------------
    // 1. 抽象事物
    // 面向对象 ： 把现实世界中的一切事物 抽象-----> 对象
    //  Student(实体) --> Entity
    //  抽象的概念（编排链） -->  对象
    //  函数式 -> 对象
    //  y = f(x)

    interface Function<I,O>  {
        O apply(I input);
    }


    static void funtionLearn(){
        Function<String, String> function = input -> {
            System.out.println("input: " + input);
            return input + "process";
        };
        String input = function.apply("input");
        System.out.println("output: " + input) ;
    }

    // 2. 算法判断环 DAG 拓扑排序

    // 3. SpringBoot 特性 SPI 自动装配

    // -----------------------------------------------------------------------------------------------------------------
}
